/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 项目名：	rumba
 * 文件名：	Task.java
 * 模块说明：	
 * 修改历史：
 * Jun 15, 2007 - lxm - 创建。
 */
package com.hd123.rumba.runtime.backprocess;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import net.sf.hibernate.HibernateException;

import org.apache.log4j.Logger;

import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.runtime.HibernateSession;

/**
 * 后台任务
 * 
 * @author lxm
 * 
 */
public class Task {

  private Logger logger = Logger.getLogger(Task.class);

  private Timer timer = new Timer();
  /** 属性：任务性质对象。 */
  private TaskNature nature;
  /** 属性：调度对象。 */
  private ITaskSchedule schedule;

  private Task() {
    // Do Nothing
  }

  /**
   * 创建一个后台任务。
   * 
   * @param nature
   *          指定任务性质对象。
   * @param schedule
   *          指定任务调度对象。
   * @throws BusinessException
   */
  public static Task create(TaskNature nature, ITaskSchedule schedule) throws BusinessException {
    assert nature != null;
    assert schedule != null;
    if (nature == null || schedule == null)
      return null;

    Task task = new Task();
    task.nature = nature;
    task.schedule = schedule;
    return task;
  }

  /**
   * 开始任务的运行。
   * <p>
   * 
   * 将会通过内部的timer安排下一次运行时间。
   * 
   * @throws BusinessException
   */
  void start() throws BusinessException {
    Date nextTime = schedule.getNextTime();
    if (nextTime != null) {
      TaskRun run = new TaskRun(this);
      this.timer.schedule(run, nextTime);
    }
  }

  /**
   * 安排任务在指定的时间被触发。
   * 
   * @param notifyTime
   *          指定的触发时间。
   * @throws BusinessException
   */
  public void start(Date notifyTime) throws BusinessException {
    if (notifyTime != null) {
      TaskRun run = new TaskRun(this);
      this.timer.schedule(run, notifyTime);
    } else
      start();
  }

  /**
   * 取消当前后台任务所有已安排的任务。
   * 
   * @throws BusinessException
   */
  void cancel() throws BusinessException {
    this.timer.cancel();
  }

  public TaskNature getNature() {
    return nature;
  }

  public ITaskSchedule getSchedule() {
    return schedule;
  }

  String getCaption() throws BusinessException {
    StringBuffer sb = new StringBuffer();
    sb.append("[");
    sb.append(nature.getCaption());
    sb.append(" | ");
    sb.append(schedule.getDescription());
    sb.append("]");
    return sb.toString();
  }

  private class TaskRun extends TimerTask {

    private Task task;

    public TaskRun(Task task) {
      assert task != null;
      this.task = task;
    }

    public void run() {
      try {
        String taskCaption = task.getCaption();
        try {
          logger.debug("TaskRun.run(): begin ... " + taskCaption);
          task.nature.trigger();
          logger.debug("TaskRun.run(): 已触发后台任务。" + taskCaption);

          Date nextTime = task.schedule.getNextTime();
          if (nextTime != null) {
            TaskRun run = new TaskRun(task);
            task.timer.schedule(run, nextTime);
            logger.debug("TaskRun.run(): 自动安排下次任务于'" + nextTime.toString() + "'。" + taskCaption);
          } else
            this.unregisterTask();
        } finally {
          // 位于独立线程内，需要确认线程结束时，HibernateSession被关闭。
          HibernateSession.closeSession();
        }
      } catch (BusinessException e) {
        logger.error("", e);
        this.unregisterTask();
      } catch (HibernateException e) {
        logger.error("", e);
        this.unregisterTask();
      }
    }

    private void unregisterTask() {
      try {
        TaskMgr.getInstance().unregisterTask(task);
        logger.debug("TaskRun.run(): 注销当前任务。" + task.getCaption());
      } catch (BusinessException e) {
        logger.error("", e);
      }
    }
  }

}
